/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tman.system.peer.tman;

import common.peer.PeerAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;

/**
 *
 * @author gianmariospacagna
 */
public class RingBuilder {

    private static final int n = 8191;

    public RingBuilder() {
    }

    static ArrayList<PeerAddress> rank(PeerAddress node, Set<PeerAddress> buf) {

        //SortedMap<Integer, PeerAddress> rankedView = new TreeMap<Integer, PeerAddress>();
        //int n = maxPeer(buf).getPeerId().intValue();
        ArrayList<PeerAddress> rankedList = new ArrayList<PeerAddress>(buf);
        Collections.sort(rankedList, new DistanceComparator(node));
        /*for (PeerAddress peer : buf) {
            if (peer != node) { 
                int dist = distance(node,peer);
                //rankedView.put(dist, peer);
                
            }
        }*/
        
        
        /*we add the succ and pred in order to not break the ring
        try {
            RingNode[] succPred = succPred(node, new ArrayList<PeerAddress>(buf));
            rankedList.add(succPred[0].getSelf());
            rankedList.add(succPred[1].getSelf());
        } catch (ExceptionViewEmpty ex) {
            //Logger.getLogger(RingBuilder.class.getName()).log(Level.SEVERE, null, ex);
        }*/
        
        //ArrayList<PeerAddress> rankedList = new ArrayList<PeerAddress>(rankedView.values());
        //rankedView.clear();
        //System.err.println("Peer "+node + " rankedList: "+rankedList);
        

        return rankedList;
    }

    public static Integer distance(PeerAddress a, PeerAddress b){
        int nodeId = a.getPeerId().intValue();
        int peerId = b.getPeerId().intValue();
        return Math.min(n - Math.abs(nodeId - peerId), Math.abs(nodeId - peerId));
    }

    public static RingNode[] succPred(PeerAddress node, Collection<PeerAddress> view) throws ExceptionViewEmpty {
        if (view.isEmpty()) {
            throw new ExceptionViewEmpty();
        } else {

            RingNode[] succPred = new RingNode[2];
            succPred[0] = minPeer(node, view);
            succPred[1] = maxPeer(node, view);

            return succPred;
        }
    }
    
    
    

    private static PeerAddress maxPeer(Collection<PeerAddress> buf) {
        PeerAddress max = buf.iterator().next();

        int maxId = max.getPeerId().intValue();


        for (PeerAddress peer : buf) {

            int peerId = peer.getPeerId().intValue();
            if (peerId > maxId) {
                max = peer;
                maxId = peerId;
            }
        }


        return max;
    }

    private static PeerAddress minPeer(Collection<PeerAddress> buf) {
        PeerAddress min = buf.iterator().next();

        int minId = min.getPeerId().intValue();


        for (PeerAddress peer : buf) {

            int peerId = peer.getPeerId().intValue();
            if (peerId < minId) {
                min = peer;
                minId = peerId;
            }
        }


        return min;
    }

    private static RingNode minPeer(PeerAddress ref, Collection<PeerAddress> buf) {

        int nodeId = ref.getPeerId().intValue();
        PeerAddress min = buf.iterator().next();

        int minId = (min.getPeerId().intValue()- nodeId + n) % n;


        for (PeerAddress peer : buf) {

            int peerId = (peer.getPeerId().intValue() - nodeId + n) % n;
            if (peerId < minId) {
                min = peer;
                minId = peerId;
            }
        }

        RingNode minNode = new RingNode(min, ref, distance(ref,min));
        return minNode;
    }

    private static RingNode maxPeer(PeerAddress ref, Collection<PeerAddress> buf) {
        int nodeId = ref.getPeerId().intValue();
        PeerAddress max = buf.iterator().next();

        int maxId = (max.getPeerId().intValue()- nodeId + n) % n;


        for (PeerAddress peer : buf) {

            int peerId = (peer.getPeerId().intValue() - nodeId + n) % n;
            if (peerId > maxId) {
                max = peer;
                maxId = peerId;
            }
        }
        
        RingNode maxNode = new RingNode(max, ref, distance(ref,max));
        return maxNode;
    }
}
